// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import (
	"internal/abi"
	"runtime/internal/sys"
	"unsafe"
)

func disableWER() {
	// 不要在系统Windows386中显示Windows错误报告对话框
	const (
		SEM_FAILCRITICALERRORS     = 0x0001
		SEM_NOGPFAULTERRORBOX      = 0x0002
		SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
		SEM_NOOPENFILEERRORBOX     = 0x8000
	)
	errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
	stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
}

// 。s和sys_windows_amd64。s 
func exceptiontramp()
func firstcontinuetramp()
func lastcontinuetramp()

func initExceptionHandler() {
	stdcall2(_AddVectoredExceptionHandler, 1, abi.FuncPCABI0(exceptiontramp))
	if _AddVectoredContinueHandler == nil || GOARCH == "386" {
		// 如果VectoredContinueHandler不可用，请为windows-386或
		// 使用SetUnhandledExceptionFilter。
		// 注意：如果正在调试，则不会调用SetUnhandledExceptionFilter处理程序。
		stdcall1(_SetUnhandledExceptionFilter, abi.FuncPCABI0(lastcontinuetramp))
	} else {
		stdcall2(_AddVectoredContinueHandler, 1, abi.FuncPCABI0(firstcontinuetramp))
		stdcall2(_AddVectoredContinueHandler, 0, abi.FuncPCABI0(lastcontinuetramp))
	}
}

// 如果上下文r描述通过调用运行时引发的异常，则IsPort返回true。中止功能。
// 
// go:nosplit 
func isAbort(r *context) bool {
	pc := r.ip()
	if GOARCH == "386" || GOARCH == "amd64" || GOARCH == "arm" {
		// 在中止的情况下，异常IP在INT3后面一个字节（这与UNIX操作系统不同）。注意，在ARM上，
		// 这意味着异常IP不再对齐。
		pc--
	}
	return isAbortPC(pc)
}

// isgoexception报告是否应将此异常转换为恐慌或抛出。
// 
// 如果我们因为堆栈溢出而中止
// 则无法避免堆栈增长。
// 
// go:nosplit 
func isgoexception(info *exceptionrecord, r *context) bool {
	// 仅在go二进制
	// （非Windows库代码）中执行指令时处理异常。
	// TODO（mwhudson）：需要循环以支持共享库
	if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
		return false
	}

	// Go将只处理一些异常。
	switch info.exceptioncode {
	default:
		return false
	case _EXCEPTION_ACCESS_VIOLATION:
	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
	case _EXCEPTION_INT_OVERFLOW:
	case _EXCEPTION_FLT_DENORMAL_OPERAND:
	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
	case _EXCEPTION_FLT_INEXACT_RESULT:
	case _EXCEPTION_FLT_OVERFLOW:
	case _EXCEPTION_FLT_UNDERFLOW:
	case _EXCEPTION_BREAKPOINT:
	case _EXCEPTION_ILLEGAL_INSTRUCTION: // 断点在arm64上以这种方式到达
	}
	return true
}

// 由sigtramp从Windows VEH处理程序调用。
// 返回值表示异常是否已被处理（异常继续执行）
// 或应提供给链中的其他处理程序（异常继续搜索）。
// 
// 这是Go代码中用于异常处理的第一个条目。这个
// 是nosplit，以避免堆栈增长，直到我们检查了
// /_EXCEPTION_断点，如果我们使g0堆栈溢出，就会引发该断点，
// 
// go:nosplit 
func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
	if !isgoexception(info, r) {
		return _EXCEPTION_CONTINUE_SEARCH
	}

	if gp.throwsplit || isAbort(r) {
		// 我们不能安全地signamic，因为它可能会增长堆栈。
		// 或者这是一个中止调用。
		// 不要再查看Windows处理程序链。
		// 现在崩溃。
		winthrow(info, r, gp)
	}

	// 在这一点之后，可以安全地增加堆栈。

	// 让它看起来像是对信号函数的调用。
	// 必须将参数传递到带外，因为
	// 增加堆栈帧将破坏
	// 展开代码。cun chu de feg
	gp.sig = info.exceptioncode
	gp.sigcode0 = info.exceptioninformation[0]
	gp.sigcode1 = info.exceptioninformation[1]
	gp.sigpc = r.ip()

	// 如果r.ip（）=0，可能会因为
	// 调用nil func而惊慌失措。不把它推到sp上会使跟踪看起来像是对runtime·sigpanic的调用。
	// （否则跟踪将在运行时结束，我们将无法查看谁出错。）
	// 如果出现故障的PC 
	// 是asyncPreempt的条目，也不要推SIGMANIC帧。在本例中，我们暂停了
	// 错误和异常处理程序之间的线程
	// 开始运行，并且我们已经推送了一个asyncPreempt调用。
	// 该异常不是来自asyncPreempt，因此不要推送一个
	// sigranic调用使其看起来像那样。相反，只要
	// 覆盖PC（请参阅第35773期）
	if r.ip() != 0 && r.ip() != abi.FuncPCABI0(asyncPreempt) {
		sp := unsafe.Pointer(r.sp())
		delta := uintptr(sys.StackAlign)
		sp = add(sp, -delta)
		r.set_sp(uintptr(sp))
		if usesLR {
			*((*uintptr)(sp)) = r.lr()
			r.set_lr(r.ip())
		} else {
			*((*uintptr)(sp)) = r.ip()
		}
	}
	r.set_ip(abi.FuncPCABI0(sigpanic0))
	return _EXCEPTION_CONTINUE_EXECUTION
}

// Windows似乎会搜索ContinueHandler的列表，甚至
// 如果ExceptionHandler返回EXCEPTION\u CONTINUE\u EXECUTION。
// 如果exceptionhandler之前也这么做，firstcontinuehandler将停止该搜索，
// 如果exceptionhandler之前也这么做的话。
// 
// 由于与exceptionhandler相同的原因，它不被拆分。
// 
// go:nosplit 
func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
	if !isgoexception(info, r) {
		return _EXCEPTION_CONTINUE_SEARCH
	}
	return _EXCEPTION_CONTINUE_EXECUTION
}

var testingWER bool

// 已到达lastcontinuehandler，因为运行时无法处理
// 当前异常。lastcontinuehandler将打印碰撞信息并退出。
// 
// 由于与exceptionhandler相同的原因，它不被拆分。
// 
// go:nosplit 
func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
	if islibrary || isarchive {
		// go DLL/archive已加载到非go程序中。
		// 如果异常不是源于go，则go运行时
		// 不应承担导致进程崩溃的责任。
		return _EXCEPTION_CONTINUE_SEARCH
	}
	if testingWER {
		return _EXCEPTION_CONTINUE_SEARCH
	}

	// VEH在SEH之前被调用，但是arm64 MSVC DLL使用SEH来捕获
	// 在运行时初始化期间的非法指令，以确定
	// CPU特性，所以如果我们到达最后一个处理程序，我们是
	// arm64，这是一条非法指令，这是来自
	// 非Go代码，然后假设发生了这种运行时探测，
	// 将其转发给SEH。
	if GOARCH == "arm64" && info.exceptioncode == _EXCEPTION_ILLEGAL_INSTRUCTION &&
		(r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip()) {
		return _EXCEPTION_CONTINUE_SEARCH
	}

	winthrow(info, r, gp)
	return 0 // 未达到
}

// go:nosplit 
func winthrow(info *exceptionrecord, r *context, gp *g) {
	_g_ := getg()

	if panicking != 0 { // 回溯已打印
		exit(2)
	}
	panicking = 1

	// 如果我们正在处理g0堆栈溢出，请吹走
	// g0堆栈边界，以便我们有空间打印回溯。如果
	// 这会以某种方式溢出堆栈，操作系统将捕获它。
	_g_.stack.lo = 0
	_g_.stackguard0 = _g_.stack.lo + _StackGuard
	_g_.stackguard1 = _g_.stackguard0

	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")

	print("PC=", hex(r.ip()), "\n")
	if _g_.m.incgo && gp == _g_.m.g0 && _g_.m.curg != nil {
		if iscgo {
			print("signal arrived during external code execution\n")
		}
		gp = _g_.m.curg
	}
	print("\n")

	_g_.m.throwing = 1
	_g_.m.caughtsig.set(gp)

	level, _, docrash := gotraceback()
	if level > 0 {
		tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
		tracebackothers(gp)
		dumpregs(r)
	}

	if docrash {
		crash()
	}

	exit(2)
}

func sigpanic() {
	g := getg()
	if !canpanic(g) {
		throw("unexpected signal during runtime execution")
	}

	switch g.sig {
	case _EXCEPTION_ACCESS_VIOLATION:
		if g.sigcode1 < 0x1000 {
			panicmem()
		}
		if g.paniconfault {
			panicmemAddr(g.sigcode1)
		}
		print("unexpected fault address ", hex(g.sigcode1), "\n")
		throw("fault")
	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
		panicdivide()
	case _EXCEPTION_INT_OVERFLOW:
		panicoverflow()
	case _EXCEPTION_FLT_DENORMAL_OPERAND,
		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
		_EXCEPTION_FLT_INEXACT_RESULT,
		_EXCEPTION_FLT_OVERFLOW,
		_EXCEPTION_FLT_UNDERFLOW:
		panicfloat()
	}
	throw("fault")
}

var (
	badsignalmsg [100]byte
	badsignallen int32
)

func setBadSignalMsg() {
	const msg = "runtime: signal received on thread not created by Go.\n"
	for i, c := range msg {
		badsignalmsg[i] = byte(c)
		badsignallen++
	}
}

// 以下内容未执行。

func initsig(preinit bool) {
}

func sigenable(sig uint32) {
}

func sigdisable(sig uint32) {
}

func sigignore(sig uint32) {
}

func badsignal2()

func raisebadsignal(sig uint32) {
	badsignal2()
}

func signame(sig uint32) string {
	return ""
}

// go:nosplit 
func crash() {
	// TODO:这个例程应该做任何需要的事情
	// 使Windows程序中止/崩溃，就像它
	// 如果go没有拦截信号一样。
	// 在Unix上，该例程将删除自定义信号
	// 处理程序，然后发出一个信号（如SIGABRT）。
	// 类似的事情应该在这里发生。
	// 暂时可以将其留空：如果崩溃返回
	// 恐慌发生后的普通出口。
}

// gsignalStack在Windows上未使用。
type gsignalStack struct{}
